﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using BaseMethods;
using Pattern.Model;

namespace Pattern.Logic
{

    public class Validation
    {
        private const int Folds = 10;
        private const int Factor = 10;

        public double TrainingValue { get { return 1 - 1.0 / Folds; } }
        public List<Sample> Samples { get; private set; }

        public double KStart { get; set; }
        public double KEnd { get; set; }
        public double KStep { get; set; }
        public double BestK { get; private set; }
        private double MseBest { get; set; }
        public string Name { get; set; }
        public int NumberOfClasses { get; set; }
        public List<OutData> OutData { get; set; }

        public Validation(SampleList samples, string name)
        {
            Samples = samples.Samples;
            KStart = 0.1;
            KEnd = 2;
            KStep = 3;
            Name = name;
            NumberOfClasses = samples.NumberOfClasses;
            OutData = new List<OutData>();
        }

        public Out Validate()
        {
            List<Sample>[] lists = Samples.ShuffleRatio(Folds);
            double min = KStart;
            double max = KEnd;
            MseBest = double.MaxValue;
            BestK = 0;

            for (int i = 0; i < KStep; i++)
            {
                double step = (max - min) / Factor;
                double mseBest = double.MaxValue;
                double kBest = 0;
                var bestPraw = 0.0;

                for (int j = 0; j <= Factor; j++)
                {
                    double k = min + j * step;
                    //test
                    var mses = new double[Folds];
                    var praws = new int[Folds];
                    //  var mseLabels = new double[Folds];
                    for (int f = 0; f < Folds; f++)
                    {
                        var result = Algorithm.Proceed(lists, f, k, NumberOfClasses);
                        mses[f] = result.Item1;
                        praws[f] = result.Item2;
                        //  mseLabels[f] = result.Item2;
                    }
                    //mse
                    var mse = mses.Average();
                    var praw = praws.Average();
                    // var mseLabel = mseLabels.Average();
                    OutData.Add(new OutData() { H = k, Mse = mse, P = praw });
                    Debug.WriteLine("MSE: {0},Praw{3}, K:{1}, Step:{2}", mse, k, i, praw);
                    //   Debug.WriteLine("MSELabel: {0}, K:{1}, Step:{2}", mseLabel, k, i);

                    if (mse < mseBest)
                    {
                        mseBest = mse;
                        kBest = k;
                        bestPraw = praw;
                    }
                }
                min = kBest - step;
                max = kBest + step;

                if (mseBest < MseBest)
                {
                    MseBest = mseBest;
                    BestK = kBest;
                    BestPraw = bestPraw;
                }
            }
            Debug.WriteLine("Best for problem {0}, MSE{1}, k:{2}, Proc:{3}", Name, MseBest, BestK, BestPraw);
            return new Out {Name = Name,NumberOfInstances = Samples.Count,OutData = OutData};
        }

        protected double BestPraw
        {
            get;
            set;
        }
    }


}
